package com.such.kit.database.dialect;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.such.kit.bean.BeanCommons;
import com.such.kit.database.DDLFormatter;
import com.such.kit.database.bean.DDLColumn;
import com.such.kit.database.bean.DDLForeignKey;
import com.such.kit.database.bean.DDLIndex;
import com.such.kit.database.bean.DDLPrimaryKey;
import com.such.kit.database.bean.DDLTable;
import com.such.kit.database.bean.DatabaseColumn;
import com.such.kit.database.bean.DatabaseForeignKey;
import com.such.kit.database.bean.DatabaseIndex;
import com.such.kit.database.bean.DatabasePrimaryKey;
import com.such.kit.database.bean.DatabaseTable;
import com.such.kit.database.exception.DatabaseException;
import com.such.kit.database.support.DDLBean;
import com.such.kit.placeholder.PlaceholderCommons;
import com.such.kit.resource.support.ReadResource;
import com.such.kit.string.StringCommons;
import com.such.kit.validate.ValidateCommons;

/**
 * @作者 SUCH
 * @日期 2017-8-25 下午4:41:58
 * @描述 数据库 DDL 工厂
 * <p>
 * resourceKey 定义规则：[方法名].[DDLBean（子类 1）属性名称].[DDLBean（子类 2）属性名称]<br>
 * 当原 resourceKey 无法满足数量需求时，可以使用 resourceKey.[序号] 进行扩充，序号必须从 1 开始且连续（原 resourceKey 必须使用）<br>
 * 例：buildCreateTableDDL、buildCreateTableDDL.1、buildCreateTableDDL.2、buildCreateTableDDL.3
 * </p>
 * <p>
 * resourceKey 引用规则：<br>
 * resourceKey 采用 xxx.xxx 的方式确认上下级关系<br>
 * 例：buildCreateTableDDL、buildCreateTableDDL.columns、buildCreateTableDDL.columns.notNull、buildCreateTableDDL.columns.columnComment<br>
 * buildCreateTableDDL 为 root<br>
 * buildCreateTableDDL.columns 为 buildCreateTableDDL 的直属下级<br>
 * buildCreateTableDDL.columns.notNull、buildCreateTableDDL.columns.columnComment 为 buildCreateTableDDL.columns 的直属下级<br>
 * resourceKey 的引用规则遵循上级只能引用直属下级<br>
 * 既 buildCreateTableDDL 只能引用 buildCreateTableDDL.columns<br>
 * 当 resourceKey 未被上级引用，则生成独立的 ddl，输出后以 ; 结束<br>
 * 当 resourceKey 被上级引用后则不生成独立的 ddl，输出后以 , 结束（集合的最后一个 , 会被删除）<br>
 * </p>
 * <p>DDL 输出顺序：最终会按照 properties 文件中 resourceKey 顺序输出</p>
 * <p>
 * params 引用规则：<br>
 * params 是从具体对象获取的数据构建的参数集<br>
 * params 会将上级的数据一直往下级传递<br>
 * 例：DatabaseTable 中有 List<DatabaseColumn> columns<br>
 * 在处理 DatabaseColumn 时候可以获取 DatabaseTable 中的属性，如：schema、name<br>
 * </p>
 */
public class DDLFactory {

	private TypeFactory TYPE;
	private String resourceName;
	private boolean formatting = true;

	/** sortMapping：properties 文件中 resourceKey 顺序，各个映射按照方法名分别存储 */
	private Map<String, List<String>> sortMapping = new HashMap<String, List<String>>();
	/** ddlTemplateMapping：存储 resourceKey 与 ddlTemplate 的映射 */
	private Map<String, String> ddlTemplateMapping = new HashMap<String, String>();
	/** subsetMapping：存储 resourceKey 与其直属下级的映射 */
	private Map<String, List<String>> subsetMapping = new HashMap<String, List<String>>();
	/** unnestedKeys：存储所有非嵌套 resourceKey（将独立输出 DDL 语句） */
	private Set<String> unnestedKeys = new HashSet<String>();
	/** resourceKeyMappings：存储 DDLBean（子类）属性与 resourceKey 的映射，各个映射按照方法名分别存储 */
	private Map<String, Map<String, String>> resourceKeyMappings = new HashMap<String, Map<String,String>>();
	/** initableMap：方法是否进行了初始化 */
	private Map<String, Boolean> initableMap = new HashMap<String, Boolean>();

	public DDLFactory(String resourceName) {
		this(resourceName, new TypeFactory(resourceName));
	}

	public DDLFactory(String resourceName, TypeFactory type) {
		this.resourceName = resourceName;
		this.TYPE = type;
	}

	public void setFormatting(boolean formatting) {
		this.formatting = formatting;
	}

	/**
	 * <p>方法名：buildCreateTableDDL</p>
	 * <p>描述：构建创建表的 DDL 语句</p>
	 * @param table DDLTable
	 * @return DLL 列表
	 */
	public List<String> buildCreateTableDDL(DDLTable table) {
		String methodName = "buildCreateTableDDL";
		return buildTableDDLHelper(methodName, table);
	}

	/**
	 * <p>方法名：buildCreateTableDDL</p>
	 * <p>描述：构建创建表的 DDL 语句</p>
	 * @param table DatabaseTable
	 * @return DLL 列表
	 */
	public List<String> buildCreateTableDDL(DatabaseTable table) {
		return buildCreateTableDDL(new DDLTable(table));
	}

	/**
	 * <p>方法名：buildDropTableDDL</p>
	 * <p>描述：构建删除表的 DDL 语句</p>
	 * @param table DatabaseTable
	 * @return DLL 列表
	 */
	public List<String> buildDropTableDDL(DDLTable table) {
		String methodName = "buildDropTableDDL";
		return buildTableDDLHelper(methodName, table);
	}

	/**
	 * <p>方法名：buildDropTableDDL</p>
	 * <p>描述：构建删除表的 DDL 语句</p>
	 * @param table DatabaseTable
	 * @return DLL 列表
	 */
	public List<String> buildDropTableDDL(DatabaseTable table) {
		return buildDropTableDDL(new DDLTable(table));
	}

	/**
	 * <p>方法名：buildRenameTableDDL</p>
	 * <p>描述：构建重命名表的 DDL 语句</p>
	 * @param table DatabaseTable
	 * @return DLL 列表
	 */
	public List<String> buildRenameTableDDL(DDLTable table) {
		String methodName = "buildRenameTableDDL";
		return buildTableDDLHelper(methodName, table);
	}

	/**
	 * <p>方法名：buildRenameTableDDL</p>
	 * <p>描述：构建重命名表的 DDL 语句</p>
	 * @param table DatabaseTable
	 * @param changedTableName 变更的表名
	 * @return DLL 列表
	 */
	public List<String> buildRenameTableDDL(DatabaseTable table, String changedTableName) {
		if (ValidateCommons.isEmpty(changedTableName)) {
			return new ArrayList<String>();
		}
		DDLTable ddlTable = new DDLTable(table);
		ddlTable.setChangedTableName(changedTableName);
		return buildRenameTableDDL(ddlTable);
	}

	private List<String> buildTableDDLHelper(String methodName, DDLTable table) {
		init(methodName, DDLTable.class);

		Map<String, List<String>> ddlsMapping = new HashMap<String, List<String>>();
		Map<String, String> resourceKeyMapping = this.resourceKeyMappings.get(methodName);
		
		Map<String, String> tableParams = table.buildRendererParams(this.resourceKeyMappings.get(methodName), this.ddlTemplateMapping, null, this.TYPE);

		List<DDLColumn> columns = table.getColumns();
		if (ValidateCommons.isNotEmpty(columns)) {
			for (DDLColumn column : columns) {
				ddlPut(ddlsMapping, StringCommons.merger(methodName, ".columns"), column.buildRendererParams(resourceKeyMapping, this.ddlTemplateMapping, tableParams, this.TYPE));
			}
		}

		List<DDLPrimaryKey> primaryKeys = table.getPrimaryKeys();
		if (ValidateCommons.isNotEmpty(primaryKeys)) {
			for (DDLPrimaryKey primaryKey : primaryKeys) {
				ddlPut(ddlsMapping, StringCommons.merger(methodName, ".primaryKeys"), primaryKey.buildRendererParams(resourceKeyMapping, this.ddlTemplateMapping, tableParams, this.TYPE));
			}
		}

		List<DDLForeignKey> foreignKeys = table.getForeignKeys();
		if (ValidateCommons.isNotEmpty(foreignKeys)) {
			for (DDLForeignKey foreignKey : foreignKeys) {
				ddlPut(ddlsMapping, StringCommons.merger(methodName, ".foreignKeys"), foreignKey.buildRendererParams(resourceKeyMapping, this.ddlTemplateMapping, tableParams, this.TYPE));
			}
		}

		List<DDLIndex> indexs = table.getIndexs();
		if (ValidateCommons.isNotEmpty(indexs)) {
			for (DDLIndex index : indexs) {
				ddlPut(ddlsMapping, StringCommons.merger(methodName, ".indexs"), index.buildRendererParams(resourceKeyMapping, this.ddlTemplateMapping, tableParams, this.TYPE));
			}
		}

		ddlPut(ddlsMapping, methodName, tableParams);

		return ddlOut(ddlsMapping, methodName);
	}

	/**
	 * <p>方法名：buildAddColumnDDL</p>
	 * <p>描述：构建新增列的 DDL 语句</p>
	 * @param column DDLColumn
	 * @return DLL 列表
	 */
	public List<String> buildAddColumnDDL(DDLColumn column) {
		String methodName = "buildAddColumnDDL";
		return buildDDLHelper(methodName, column);
	}

	/**
	 * <p>方法名：buildAddColumnDDL</p>
	 * <p>描述：构建新增列的 DDL 语句</p>
	 * @param column DatabaseColumn
	 * @return DLL 列表
	 */
	public List<String> buildAddColumnDDL(DatabaseColumn column) {
		return buildAddColumnDDL(new DDLColumn(column));
	}

	/**
	 * <p>方法名：buildModifyColumnDDL</p>
	 * <p>描述：构建修改列的 DDL 语句</p>
	 * @param column DDLColumn
	 * @return DLL 列表
	 */
	public List<String> buildModifyColumnDDL(DDLColumn column) {
		String methodName = "buildModifyColumnDDL";
		return buildDDLHelper(methodName, column);
	}

	/**
	 * <p>方法名：buildModifyColumnDDL</p>
	 * <p>描述：构建修改列的 DDL 语句</p>
	 * @param column DatabaseColumn
	 * @return DLL 列表
	 */
	public List<String> buildModifyColumnDDL(DatabaseColumn column) {
		return buildModifyColumnDDL(new DDLColumn(column));
	}

	/**
	 * <p>方法名：buildDropColumnDDL</p>
	 * <p>描述：构建删除列的 DDL 语句</p>
	 * @param column DDLColumn
	 * @return DLL 列表
	 */
	public List<String> buildDropColumnDDL(DDLColumn column) {
		String methodName = "buildDropColumnDDL";
		return buildDDLHelper(methodName, column);
	}

	/**
	 * <p>方法名：buildDropColumnDDL</p>
	 * <p>描述：构建删除列的 DDL 语句</p>
	 * @param column DatabaseColumn
	 * @return DLL 列表
	 */
	public List<String> buildDropColumnDDL(DatabaseColumn column) {
		return buildDropColumnDDL(new DDLColumn(column));
	}

	/**
	 * <p>方法名：buildRenameColumnDDL</p>
	 * <p>描述：构建重命名列的 DDL 语句</p>
	 * @param column DDLColumn
	 * @return DLL 列表
	 */
	public List<String> buildRenameColumnDDL(DDLColumn column) {
		String methodName = "buildRenameColumnDDL";
		return buildDDLHelper(methodName, column);
	}

	/**
	 * <p>方法名：buildRenameColumnDDL</p>
	 * <p>描述：构建重命名列的 DDL 语句</p>
	 * @param column DatabaseColumn
	 * @return DLL 列表
	 */
	public List<String> buildRenameColumnDDL(DatabaseColumn column) {
		return buildRenameColumnDDL(new DDLColumn(column));
	}

	/**
	 * <p>方法名：buildAddPrimaryKeyDDL</p>
	 * <p>描述：构建新增主键的 DDL 语句</p>
	 * @param primaryKey DDLPrimaryKey
	 * @return DLL 列表
	 */
	public List<String> buildAddPrimaryKeyDDL(DDLPrimaryKey primaryKey) {
		String methodName = "buildAddPrimaryKeyDDL";
		return buildDDLHelper(methodName, primaryKey);
	}

	/**
	 * <p>方法名：buildAddPrimaryKeyDDL</p>
	 * <p>描述：构建新增主键的 DDL 语句</p>
	 * @param primaryKeys DatabasePrimaryKey
	 * @return DLL 列表
	 */
	public List<String> buildAddPrimaryKeyDDL(List<DatabasePrimaryKey> primaryKeys) {
		return buildAddPrimaryKeyDDL(new DDLPrimaryKey(primaryKeys));
	}

	/**
	 * <p>方法名：buildDropPrimaryKeyDDL</p>
	 * <p>描述：构建删除主键的 DDL 语句</p>
	 * @param primaryKey DDLPrimaryKey
	 * @return DLL 列表
	 */
	public List<String> buildDropPrimaryKeyDDL(DDLPrimaryKey primaryKey) {
		String methodName = "buildDropPrimaryKeyDDL";
		return buildDDLHelper(methodName, primaryKey);
	}

	/**
	 * <p>方法名：buildDropPrimaryKeyDDL</p>
	 * <p>描述：构建删除主键的 DDL 语句</p>
	 * @param primaryKeys DatabasePrimaryKey
	 * @return DLL 列表
	 */
	public List<String> buildDropPrimaryKeyDDL(List<DatabasePrimaryKey> primaryKeys) {
		return buildDropPrimaryKeyDDL(new DDLPrimaryKey(primaryKeys));
	}

	/**
	 * <p>方法名：buildRenamePrimaryKeyDDL</p>
	 * <p>描述：构建重命名主键的 DDL 语句</p>
	 * @param primaryKey DDLPrimaryKey
	 * @return DLL 列表
	 */
	public List<String> buildRenamePrimaryKeyDDL(DDLPrimaryKey primaryKey) {
		String methodName = "buildRenamePrimaryKeyDDL";
		return buildDDLHelper(methodName, primaryKey);
	}

	/**
	 * <p>方法名：buildRenamePrimaryKeyDDL</p>
	 * <p>描述：构建重命名主键的 DDL 语句</p>
	 * @param primaryKeys DatabasePrimaryKey
	 * @return DLL 列表
	 */
	public List<String> buildRenamePrimaryKeyDDL(List<DatabasePrimaryKey> primaryKeys) {
		return buildRenamePrimaryKeyDDL(new DDLPrimaryKey(primaryKeys));
	}

	/**
	 * <p>方法名：buildAddForeignKeyDDL</p>
	 * <p>描述：构建新增外键的 DDL 语句</p>
	 * @param foreignKey DDLForeignKey
	 * @return DLL 列表
	 */
	public List<String> buildAddForeignKeyDDL(DDLForeignKey foreignKey) {
		String methodName = "buildAddForeignKeyDDL";
		return buildDDLHelper(methodName, foreignKey);
	}

	/**
	 * <p>方法名：buildAddForeignKeyDDL</p>
	 * <p>描述：构建新增外键的 DDL 语句</p>
	 * @param foreignKeys DatabaseForeignKey
	 * @return DLL 列表
	 */
	public List<String> buildAddForeignKeyDDL(List<DatabaseForeignKey> foreignKeys) {
		return buildAddForeignKeyDDL(new DDLForeignKey(foreignKeys));
	}

	/**
	 * <p>方法名：buildDropForeignKeyDDL</p>
	 * <p>描述：构建删除外键的 DDL 语句</p>
	 * @param foreignKey DDLForeignKey
	 * @return DLL 列表
	 */
	public List<String> buildDropForeignKeyDDL(DDLForeignKey foreignKey) {
		String methodName = "buildDropForeignKeyDDL";
		return buildDDLHelper(methodName, foreignKey);
	}

	/**
	 * <p>方法名：buildDropForeignKeyDDL</p>
	 * <p>描述：构建删除外键的 DDL 语句</p>
	 * @param foreignKeys DatabaseForeignKey
	 * @return DLL 列表
	 */
	public List<String> buildDropForeignKeyDDL(List<DatabaseForeignKey> foreignKeys) {
		return buildDropForeignKeyDDL(new DDLForeignKey(foreignKeys));
	}

	/**
	 * <p>方法名：buildRenameForeignKeyDDL</p>
	 * <p>描述：构建重命名外键的 DDL 语句</p>
	 * @param foreignKey DDLForeignKey
	 * @return DLL 列表
	 */
	public List<String> buildRenameForeignKeyDDL(DDLForeignKey foreignKey) {
		String methodName = "buildRenameForeignKeyDDL";
		return buildDDLHelper(methodName, foreignKey);
	}

	/**
	 * <p>方法名：buildRenameForeignKeyDDL</p>
	 * <p>描述：构建重命名外键的 DDL 语句</p>
	 * @param foreignKeys DatabaseForeignKey
	 * @return DLL 列表
	 */
	public List<String> buildRenameForeignKeyDDL(List<DatabaseForeignKey> foreignKeys) {
		return buildRenameForeignKeyDDL(new DDLForeignKey(foreignKeys));
	}

	/**
	 * <p>方法名：buildAddIndexDDL</p>
	 * <p>描述：构建新增索引的 DDL 语句</p>
	 * @param index DDLIndex
	 * @return DLL 列表
	 */
	public List<String> buildAddIndexDDL(DDLIndex index) {
		String methodName = "buildAddIndexDDL";
		return buildDDLHelper(methodName, index);
	}

	/**
	 * <p>方法名：buildAddIndexDDL</p>
	 * <p>描述：构建新增索引的 DDL 语句</p>
	 * @param indexs DatabaseIndex
	 * @return DLL 列表
	 */
	public List<String> buildAddIndexDDL(List<DatabaseIndex> indexs) {
		return buildAddIndexDDL(new DDLIndex(indexs));
	}

	/**
	 * <p>方法名：buildDropIndexDDL</p>
	 * <p>描述：构建删除索引的 DDL 语句</p>
	 * @param index DDLIndex
	 * @return DLL 列表
	 */
	public List<String> buildDropIndexDDL(DDLIndex index) {
		String methodName = "buildDropIndexDDL";
		return buildDDLHelper(methodName, index);
	}

	/**
	 * <p>方法名：buildDropIndexDDL</p>
	 * <p>描述：构建删除索引的 DDL 语句</p>
	 * @param indexs DatabaseIndex
	 * @return DLL 列表
	 */
	public List<String> buildDropIndexDDL(List<DatabaseIndex> indexs) {
		return buildDropIndexDDL(new DDLIndex(indexs));
	}

	/**
	 * <p>方法名：buildRenameIndexDDL</p>
	 * <p>描述：构建重命名索引的 DDL 语句</p>
	 * @param index DDLIndex
	 * @return DLL 列表
	 */
	public List<String> buildRenameIndexDDL(DDLIndex index) {
		String methodName = "buildRenameIndexDDL";
		return buildDDLHelper(methodName, index);
	}

	/**
	 * <p>方法名：buildRenameIndexDDL</p>
	 * <p>描述：构建重命名索引的 DDL 语句</p>
	 * @param indexs DatabaseIndex
	 * @return DLL 列表
	 */
	public List<String> buildRenameIndexDDL(List<DatabaseIndex> indexs) {
		return buildRenameIndexDDL(new DDLIndex(indexs));
	}

	private <T> List<String> buildDDLHelper(String methodName, DDLBean<T> bean) {
		init(methodName, bean.getClass());

		Map<String, List<String>> ddlsMapping = new HashMap<String, List<String>>();
		Map<String, String> resourceKeyMapping = this.resourceKeyMappings.get(methodName);

		ddlPut(ddlsMapping, methodName, bean.buildRendererParams(resourceKeyMapping, this.ddlTemplateMapping, null, this.TYPE));

		return ddlOut(ddlsMapping, methodName);
	}

	private void init(String methodName, Class<?> argumentClass) {
		// 检查 methodName 是否进行过初始
		Boolean initable = this.initableMap.get(methodName);
		if (ValidateCommons.isNotEmpty(initable) && initable.booleanValue()) {
			return;
		} else {
			this.initableMap.put(methodName, true);
		}

		// 抓取所有与 methodName 相关的 resourceKey
		List<String> resourceKeys = new ArrayList<String>();
		for (String key : ReadResource.getKeys(this.resourceName)) {
			if (key.startsWith(methodName)) {
				resourceKeys.add(key);
			}
		}
		// 初始化 sortMapping
		this.sortMapping.put(methodName, resourceKeys);

		// 初始化 ddlTemplateMapping，准备 unnestedKeys
		for (String resourceKey : resourceKeys) {
			String ddlTemplate = ReadResource.getValue(this.resourceName, resourceKey);
			if (ValidateCommons.isEmpty(ddlTemplate, false)) {
				throw new DatabaseException(StringCommons.merger("未在 [", this.resourceName, "] 中找到 [", resourceKey, "] 对应的 ddl 模板"));
			}
			this.ddlTemplateMapping.put(resourceKey, ddlTemplate);
			this.unnestedKeys.add(resourceKey);
		}

		for (String checkerKey : resourceKeys) {
			// 初始化 subsetMapping
			int levelChecker = checkerKey.split("\\.").length + 1;
			List<String> subset = new ArrayList<String>();
			for (String resourceKey : resourceKeys) {
				int level = resourceKey.split("\\.").length;
				if (resourceKey.startsWith(checkerKey) && level == levelChecker) {
					subset.add(resourceKey);
				}
			}
			this.subsetMapping.put(checkerKey, subset);

			// 初始化 unnestedKeys
			String ddlTemplate = this.ddlTemplateMapping.get(checkerKey);
			List<String> nestedKeys = PlaceholderCommons.getInnerKeys(ddlTemplate);
			for (String nestedKey : nestedKeys) {
				this.unnestedKeys.remove(nestedKey);
			}
		}

		// 初始化 resourceKeyMapping
		initResourceKeyMapping(methodName, methodName, argumentClass);
	}

	private void initResourceKeyMapping(String methodName, String prefix, Class<?> argumentClass) {
		Map<String, String> resourceKeyMapping = new HashMap<String, String>();
		List<String> attributeNames = BeanCommons.getAttributeNames(argumentClass);
		Map<String, Type> attributeGenericityTypes = BeanCommons.getAttributeGenericityTypes(argumentClass);
		for (String attributeName : attributeNames) {
			int index = 1;
			// resourceKey 格式：prefix.attributeName
			String resourceKey = StringCommons.merger(prefix, ".", attributeName);
			// 检查 resourceKey 是否真的存在
			while (this.ddlTemplateMapping.containsKey(resourceKey)) {
				resourceKeyMapping.put(DDLBean.buildPlaceholderKey(attributeName, argumentClass), resourceKey);
				Type attributeGenericityType = attributeGenericityTypes.get(attributeName);
				if (ValidateCommons.isNotEmpty(attributeGenericityType)) {
					String typeName = attributeGenericityType.toString();
					// 检查属性类型是否为 DDLBean（子类），如果是则进行递归
					if (typeName.indexOf(BeanCommons.getName(DDLTable.class)) > 0) {
						initResourceKeyMapping(methodName, resourceKey, DDLTable.class);
					} else if (typeName.indexOf(BeanCommons.getName(DDLColumn.class)) > 0) {
						initResourceKeyMapping(methodName, resourceKey, DDLColumn.class);
					} else if (typeName.indexOf(BeanCommons.getName(DDLPrimaryKey.class)) > 0) {
						initResourceKeyMapping(methodName, resourceKey, DDLPrimaryKey.class);
					} else if (typeName.indexOf(BeanCommons.getName(DDLForeignKey.class)) > 0) {
						initResourceKeyMapping(methodName, resourceKey, DDLForeignKey.class);
					} else if (typeName.indexOf(BeanCommons.getName(DDLIndex.class)) > 0) {
						initResourceKeyMapping(methodName, resourceKey, DDLIndex.class);
					}
				}
				// 处理 resourceKey 序号扩展
				resourceKey = StringCommons.merger(resourceKey, ".", index);
				index++;
			}
		}

		Map<String, String> tempResourceKeyMapping = this.resourceKeyMappings.get(methodName);
		if (ValidateCommons.isNotEmpty(tempResourceKeyMapping)) {
			resourceKeyMapping.putAll(tempResourceKeyMapping);
		}
		this.resourceKeyMappings.put(methodName, resourceKeyMapping);
	}

	private void ddlPut(Map<String, List<String>> ddlsMapping, String resourceKey, Map<String, String> params) {
		List<String> subset = this.subsetMapping.get(resourceKey);
		if (ValidateCommons.isNotEmpty(subset)) {
			for (String sub : subset) {
				// 获取 resourceKey 子集，当其为非嵌套 DDL 模板时，将对应的 DDL 模板渲染后存入 ddlsMapping
				if (this.unnestedKeys.contains(sub)) {
					ddlPut(ddlsMapping, sub, params.get(sub));
				}
			}
		}
		String ddlTemplate = this.ddlTemplateMapping.get(resourceKey);
		if (ValidateCommons.isNotEmpty(ddlTemplate)) {
			/*
			 * 处理嵌套 DDL 模板
			 * 通常只有在跨层级的情况下需要处理嵌套 DDL 模板
			 * 如：buildCreateTableDDL、buildCreateTableDDL.columns、buildCreateTableDDL.columns.default、buildCreateTableDDL.columns.comment
			 * buildCreateTableDDL、buildCreateTableDDL.columns 属于一个层级
			 * buildCreateTableDDL.columns、buildCreateTableDDL.columns.default、buildCreateTableDDL.columns.comment 属于一个层级
			 * 在处理 buildCreateTableDDL.columns 层级时，层级节点及其非嵌套节点将存储在 ddlsMapping 中，如：buildCreateTableDDL.columns、buildCreateTableDDL.columns.comment
			 * 在处理 buildCreateTableDDL 层级时，需要使用 buildCreateTableDDL.columns 中的数据，而 buildCreateTableDDL.columns 数据存储在 ddlsMapping 中
			 * 因此在跨层级时，需要处理嵌套 DDL 模板
			 */
			List<String> nestedKeys = PlaceholderCommons.getInnerKeys(ddlTemplate);
			if (ValidateCommons.isNotEmpty(nestedKeys)) {
				for (String nestedKey : nestedKeys) {
					List<String> ddls = ddlsMapping.get(nestedKey);
					if (ValidateCommons.isNotEmpty(ddls)) {
						for (String ddl : ddls) {
							String tempDDL = params.get(nestedKey);
							if (ValidateCommons.isEmpty(tempDDL)) {
								params.put(nestedKey, ddl);
							} else {
								params.put(nestedKey, StringCommons.merger(tempDDL, ", ", ddl));
							}
						}
					}
				}
			}

			// 将 resourceKey 对应的 DDL 模板渲染后存入 ddlsMapping
			ddlPut(ddlsMapping, resourceKey, PlaceholderCommons.replacePlaceholder(ddlTemplate, params));
		}
	}

	private void ddlPut(Map<String, List<String>> ddlsMapping, String resourceKey, String ddl) {
		if (ValidateCommons.isNotEmpty(ddl)) {
			ddl = ddl.trim();
		}

		List<String> ddls = ddlsMapping.get(resourceKey);
		if (ValidateCommons.isEmpty(ddls)) {
			ddls = new ArrayList<String>();
		}
		ddls.add(ddl);
		ddlsMapping.put(resourceKey, ddls);
	}

	private List<String> ddlOut(Map<String, List<String>> ddlsMapping, String methodName) {
		List<String> ddlOut = new ArrayList<String>();
		List<String> resourceKeys = this.sortMapping.get(methodName);
		if (ValidateCommons.isNotEmpty(resourceKeys)) {
			for (String resourceKey : resourceKeys) {
				// 检查 resourceKey 是否为非嵌套
				if (this.unnestedKeys.contains(resourceKey)) {
					List<String> ddls = ddlsMapping.get(resourceKey);
					if (ValidateCommons.isNotEmpty(ddls)) {
						for (String ddl : ddls) {
							if (ValidateCommons.isNotEmpty(ddl)) {
								if (this.formatting) {
									ddl = DDLFormatter.format(ddl);
								}
								ddlOut.add(ddl);
							}
						}
					}
				}
			}
		}
		return ddlOut;
	}

	/**
	 * <p>方法名：toString</p>
	 * <p>描述：将生成的 DDL 集合输出为字符串</p>
	 * @param ddls DDL 集合
	 * @return ddl
	 */
	public static String toString(List<String> ddls) {
		StringBuffer ddlBuf = new StringBuffer();
		if (ValidateCommons.isNotEmpty(ddls)) {
			for (String ddl : ddls) {
				if (ValidateCommons.isNotEmpty(ddl)) {
					if (ddlBuf.length() > 0) {
						ddlBuf.append(StringCommons.NEW_LINE);
					}
					ddlBuf.append(ddl).append(";");
				}
			}
		}
		return ddlBuf.toString();
	}

}
